#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <pthread.h>
#include <queue> //队列

using namespace std;
#define NUM 10

class BlockQueue{
  private:
    queue<int> q;
    int cap;
    pthread_mutex_t lock;
    pthread_cond_t full;//环境变量
    pthread_cond_t emp;

    bool IsEmpty()
    {
      return q.size() == 0;
    }

    bool IsFull()
    {
      return q.size() == cap;
    }

  public:
    BlockQueue(int _cap = NUM)
      :cap(_cap)
    {
      pthread_mutex_init(&lock, nullptr);
      pthread_cond_init(&full, nullptr);
      pthread_cond_init(&emp, nullptr);
    }

    //生产者push数据
    void PushData(const int& in)
    {
      pthread_mutex_lock(&lock);
      //临界资源
      while(IsFull()){
        pthread_cond_signal(&emp);
        cout<<"队列已满， 生产暂停"<<endl;
        pthread_cond_wait(&emp, &lock);
      }
      q.push(in);
      pthread_mutex_unlock(&lock);
    }

    //消费者pop数据
    void PopData(int& out)
    {
      pthread_mutex_lock(&lock);
      while(IsEmpty()){
        pthread_cond_signal(&full);
        cout<<"队列 空 ， 停止消费"<<endl;
        pthread_cond_wait(&emp, &lock);
      }
      out = q.front();
      q.pop();
      pthread_mutex_unlock(&lock);
    }

    ~BlockQueue()
    {
      pthread_mutex_destroy(&lock);
      pthread_cond_destroy(&full);
      pthread_cond_destroy(&emp);
    }
};

void *consumer(void* arg)
{
  BlockQueue *bq = (BlockQueue*) arg;
  int data;
  while(1){
    bq->PopData(data);
    cout<<"Consumer data done : " << data << endl;
  }
}

void *producer(void *arg)
{
  BlockQueue *bq = (BlockQueue*) arg;
  srand((unsigned long)time(nullptr)); //随机数种子
  while(1){
    int data = rand()%10;
    bq->PushData(data);
    cout<<"producer data done: "<< data << endl;
  }
}
int main()
{
  BlockQueue bq;
  pthread_t c,p;
  pthread_create(&c, nullptr, consumer, (void*)&bq);
  pthread_create(&p, nullptr, producer, (void*)&bq);

  pthread_join(c, nullptr);
  pthread_join(p, nullptr);
  return 20;
}
